import json
from flask import Flask, jsonify, request
from BlcokChain import BlockChain
from ecdsa import SigningKey

blockchain = BlockChain()
signingkey = SigningKey.generate()

class LocalBlockChain():

    def __init__(self, h, p):
        self.h = h
        self.p = p
        blockchain.register_node(f"http://{h}:{p}")
        blockchain.register_user("User_A", signingkey.get_verifying_key().to_string())
        self.blockchain = blockchain


    def transactions_applying(self, sender, recipient, amount):
        isUpdate,message=self.update()
        vc = signingkey.sign(json.dumps({
            'transaction_id': self.blockchain.transaction_id,
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        },sort_keys=True).encode())
        index = self.blockchain.new_transaction(sender, recipient, amount, vc)
        b1 = self.blockchain.valid_transaction(index)
        index = blockchain.new_transaction(sender, recipient, amount, vc)
        b2 = blockchain.valid_transaction(index)
        blockchain.transactions_pool=blockchain.transactions_pool[:-1]
        if (b1):
            message += "Local varification passed. "
        else:
            message += 'Local varification failed. '
        if (b2):
            message += "Nodes Network verification passed. "
        else:
            message += "Nodes Network verification failed. "
        if (b1 and b2):
            message += f"The transaction will be added to block {len(self.blockchain.chain)}. "
            self.blockchain.execute_transactions()
        else:
            self.blockchain.transactions_pool = self.blockchain.transactions_pool[:-2]
        return (b1 and b2), message

    def update(self):
        #更新本地区块链
        self.blockchain.user = blockchain.user
        self.blockchain.nodes = blockchain.nodes
        blockchain.resolve_conflicts()
        isUpdate = self.blockchain.resolve_conflicts()
        message = ""
        if (isUpdate):
            message += "Our chain has been updated.\n"
        return isUpdate, message


    def mine(self,account):
        #挖矿出块
        last_block = self.blockchain.last_block
        last_proof = last_block['proof']
        proof = self.blockchain.proof_of_work(last_proof)
        valid,message=self.transactions_applying("0",account,1)
        if(valid is False):
            return False, message,None
        previous_hash = self.blockchain.hash(last_block)
        block = self.blockchain.new_block(proof, previous_hash)
        isBlockOut,m=self.update()
        if(isBlockOut):
            message+='Block out failed.\n'
            return False,message,None
        message+='New Block Forged.\n'
        return True,message,block


app = Flask(__name__)
localblockchain=LocalBlockChain('localhost',5000)


# 进行挖矿请求
@app.route('/mine', methods=['POST'])
def mine():
    value = request.get_json()
    isblockout,message,block=localblockchain.mine(value['account'])
    if(isblockout):
        response = {
            'index': block['index'],
            'transactions': block['transactions'],
            'proof': block['proof'],
            'previous_hash': block['previous_hash'],
            'message': message
        }
        return jsonify(response),201
    return jsonify({'message':message}),201


# 创建交易请求
@app.route('/transactions/new', methods=['POST'])
def new_transactions():
    values = request.get_json()

    # 检查所需要的字段是否位于POST的data中
    required = ['sender', 'recipient', 'amount']
    if not all(k in values for k in required):
        return 'Missing values', 400

    # 创建一个新的事物
    valid,message=localblockchain.transactions_applying(values['sender'],values['recipient'],values['amount'])
    if(valid):
        response={
            'sender':values['sender'],
            'recipient':values['recipient'],
            'amount':values['amount'],
            'message':message
        }
        return jsonify(response),201
    return jsonify({'message':message}),201


# 获取所有快信息
@app.route('/chain', methods=['GET'])
def full_chain():
    response = {
        'chain': localblockchain.blockchain.chain,
        'length': len(localblockchain.blockchain.chain),
    }
    return jsonify(response), 200


# 解决冲突
@app.route('/nodes/resolve', methods=['GET'])
def consensus():
    replaced = localblockchain.update()

    if replaced:
        response = {
            'message': 'Our chain was replaced',
            'new_chain': localblockchain.blockchain.chain
        }
    else:
        response = {
            'message': 'Our chain is authoritative',
            'chain': localblockchain.blockchain.chain
        }

    return jsonify(response), 200





if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000)